/*
* Copyright (C) 2012-2014 qar
* License: http://www.gnu.org/licenses/gpl.html GPL version 2
*/

#include "crypto/hasher.h"
#include "crypto/hash/hashfunction.h"
#include "crypto/hash/hashfunctionnull.h"
#include "crypto/hash/hashfunctionmd5.h"
#include "crypto/hash/hashfunctionsha1.h"
#include "util.h"

Hasher::Hasher(Hasher::IntegrityAlgorithm algorithm)
    : algorithm(algorithm),
      hashFunction(NULL)
{
    setAlgorithm(algorithm);
}

Hasher::~Hasher()
{
    delete hashFunction;
    hashFunction = NULL;
}

void Hasher::setAlgorithm(Hasher::IntegrityAlgorithm algorithm)
{
    delete hashFunction;
    hashFunction = NULL;

    this->algorithm = algorithm;
    if (algorithm == Hasher::NoIntegrity) {
        // Nothing to do
    } else if (algorithm == Hasher::Md5) {
        hashFunction = new HashFunctionMd5();
    } else if (algorithm == Hasher::Sha1) {
        hashFunction = new HashFunctionSha1();
    } else {
        ASSERT(false);
    }
}

Hasher::IntegrityAlgorithm Hasher::getAlgorithm() const
{
    return algorithm;
}

QString Hasher::getAlgorithmName() const
{
    return hashFunction->getAlgorithmName();
}

qint64 Hasher::hashSize() const
{
    return hashFunction->hashSize();
}

void Hasher::reset()
{
    hashFunction->reset();
}

void Hasher::addData(const QByteArray &data)
{
    addData(data.constData(), data.length());
}

void Hasher::addData(const char *data, int length)
{
    hashFunction->addData(data, length);
}

QByteArray Hasher::result() const
{
    return hashFunction->result();
}

QByteArray Hasher::offlineHash(const QByteArray &data) const
{
    return hashFunction->offlineHash(data);
}

QByteArray Hasher::offlineHash(const QByteArray &data, Hasher::IntegrityAlgorithm algorithm)
{
    Hasher hasher(algorithm);
    hasher.addData(data);
    return hasher.result();
}

bool Hasher::toStream(QDataStream &s)
{
    qint32 integrityAlgorithmEncoded = algorithm;
    s << integrityAlgorithmEncoded;
    return s.status() == QDataStream::Ok;
}

bool Hasher::fromStream(QDataStream &s)
{
    qint32 integrityAlgorithmEncoded;
    s >> integrityAlgorithmEncoded;
    if (s.status() != QDataStream::Ok)
        return false;

    if (integrityAlgorithmEncoded == Hasher::NoIntegrity) {
        setAlgorithm(Hasher::NoIntegrity);
    } else if (integrityAlgorithmEncoded == Hasher::Md5) {
        setAlgorithm(Hasher::Md5);
    } else if (integrityAlgorithmEncoded == Hasher::Sha1) {
        setAlgorithm(Hasher::Sha1);
    } else {
        return false;
    }
    return true;
}
